package generation;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import ec.EvolutionState;
import ec.Individual;
import ec.Subpopulation;
import ec.multiobjective.MultiObjectiveFitness;
import ec.simple.SimpleStatistics;
import ec.util.*;

public class PasswordGenerationWithMutation {
	public static ArrayList<Individual> evaluatedIndiv = new ArrayList<Individual>();

	private String userKeyWord = null;
	private int maxSize = 0;
	private int nbrEchantillon;
	private EvolutionState state;
	private int speedOfComplexification;
	private int maxGeneration;

	public PasswordGenerationWithMutation(String userKeyWord, int maxSize,
			int nbrEchantillon, int speedOfComplexification, int maxGeneration) {
		this.userKeyWord = userKeyWord;
		if (maxSize - userKeyWord.length() >= 0)
			this.maxSize = maxSize;
		this.nbrEchantillon = nbrEchantillon;
		this.speedOfComplexification = speedOfComplexification;
		this.maxGeneration = maxGeneration;
		state = null;
	}

	private void initilizeGenerator(File parameterFile) {
		if (state == null) {
			ParameterDatabase paramDB = null;
			try {
				paramDB = new ParameterDatabase(parameterFile, new String[] {
						"-file", parameterFile.getCanonicalPath() });
			} catch (IOException e) {
				System.out.println("Error: " + e);
			}

			ParameterDatabase child = new ParameterDatabase();
			child.addParent(paramDB);
			speedOfComplexification++;
			child.set(new Parameter(Transformation.P_OURVARIABLE + "."
					+ Transformation.I_AUTONOMEGENERATION), ""
					+ speedOfComplexification);
			child.set(new Parameter(Transformation.P_OURVARIABLE + "."
					+ Transformation.P_KEYWORD), userKeyWord);
			child.set(new Parameter(Transformation.P_OURVARIABLE + "."
					+ Transformation.I_MAXSIZE), "" + maxSize);
			child.set(new Parameter("generations"), "" + maxGeneration
					* speedOfComplexification);

			state = ec.Evolve.initialize(child, 0);
			state.startFresh();
		}
	}

	public ArrayList<Individual> generatePassword() {
		ArrayList<Individual> modifyKeyWord = new ArrayList<Individual>();
		if (state == null) {
			initilizeGenerator(new File("src/transformation.params"));
		}
		int result = EvolutionState.R_NOTDONE;
		int nbrGen = 0;
		while (result == EvolutionState.R_NOTDONE) {
			result = state.evolve();
			nbrGen++;
			Transformation.first = true;

			if (nbrGen % Transformation.getNumberOfAutonomeGeneration() == 0) {
				Individual[] inds = ((SimpleStatistics) (state.statistics))
						.getBestSoFar();
				float[] bestFitness = ((MultiObjectiveFitness) (inds[0].fitness))
						.getObjectives();
				float bestNormalizeFitness = normalizeFitness(bestFitness);

				evaluatedIndiv = new ArrayList<Individual>();

				Subpopulation[] subpop = state.population.subpops;
				Individual[] indiv = subpop[0].individuals;

				double marge = 0;
				while (modifyKeyWord.size() < nbrEchantillon) {
					for (int i = 0; i < indiv.length; i++) {
						float indivFitness = normalizeFitness(((MultiObjectiveFitness) (indiv[i].fitness))
								.getObjectives());
						if (indivFitness >= bestNormalizeFitness - marge
								&& indivFitness < bestNormalizeFitness - marge
										+ bestNormalizeFitness / 100) {
							modifyKeyWord.add(indiv[i]);
						}
					}
					marge += bestNormalizeFitness / 1000;
				}
				return modifyKeyWord;
			}
		}
		return new ArrayList<Individual>();
	}

	private float normalizeFitness(float[] bestFiteness) {
		return (float) (Math.sqrt((Math.pow(bestFiteness[0], 2) + Math.pow(
				bestFiteness[1], 2)) / 2));
	}

	public int getNbrEchantillon() {
		return nbrEchantillon;
	}

	public void setNbrEchantillon(int nbrEchantillon) {
		this.nbrEchantillon = nbrEchantillon;
	}

	public EvolutionState getState() {
		return state;
	}

	public void setState(EvolutionState state) {
		this.state = state;
	}
}